/*
 * This code was created by Jeff Molofee '99
 * (ported to Linux/SDL by Ti Leggett '01)
 *
 * If you've found this code useful, please let me know.
 *
 * Visit Jeff at http://nehe.gamedev.net/
 *
 * or for port-specific comments, questions, bugreports etc.
 * email to leggett@eecs.tulane.edu
 */

#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "q3bsp.hpp"
#include "q3map.hpp"
#include "gl_extensions.hpp"

/* screen width, height, and bit depth */
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP     16

/* Setup our booleans */
#define TRUE  1
#define FALSE 0

/* This is our SDL surface */
SDL_Surface *surface;

q3map map;

static const int nKeys = 322;   //billentyu kombinaciok
unsigned char keys[nKeys];

/* function to release/destroy our resources and restoring the old desktop */
void Quit(int returnCode){
/* clean up the window */
 SDL_Quit();
/* and exit appropriately */
 map.destroy_map();
 exit(returnCode);
}

/* function to reset our viewport after a window resize */
int resizeWindow(int width,int height){
/* Height / width ration */
 GLfloat ratio;
/* Protect against a divide by zero */
 if(height== 0){
  height = 1;
 }
 ratio= (GLfloat)width/(GLfloat)height;
/* Setup our viewport. */
 glViewport(0,0,(GLint)width,(GLint)height);
/* change to the projection matrix and set our viewing volume. */
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
/* Set our perspective */
 gluPerspective(45.0f,ratio,0.1f,10000.0f);
/* Make sure we're chaning the model view and not the projection */
 glMatrixMode(GL_MODELVIEW);
/* Reset The View */
 glLoadIdentity();
 return(TRUE);
}

/* function to handle key press events */
void handleKeyPress(SDL_keysym* keysym){
 switch(keysym->sym){
  case SDLK_ESCAPE:
/* ESC key was pressed */
   Quit(0);
   break;
  case SDLK_F1:
/* F1 key was pressed
* this toggles fullscreen mode
*/
   SDL_WM_ToggleFullScreen( surface );
   break;
  default:
   break;
  }
 return;
}

/* general OpenGL initialization function */
int initGL(void){
/* Enable smooth shading */
 glShadeModel(GL_SMOOTH);
/* Set the background black */
 glClearColor(0.0f,0.0f,0.0f,0.0f);
/* Depth buffer setup */
 glClearDepth(1.0f);
/* Enables Depth Testing */
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_VERTEX_ARRAY);
 glEnable(GL_TEXTURE_COORD_ARRAY);
/* The Type Of Depth Test To Do */
 glDepthFunc(GL_LEQUAL);
/* Really Nice Perspective Calculations */
 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
 glEnable(GL_TEXTURE_2D);
 glEnable(GL_CULL_FACE);
 glFrontFace(GL_CW);
 return TRUE;
}

/* Here goes our drawing code */
int drawGLScene(void){
/* These are to calculate our fps */
 static GLint T0= 0;
 static GLint Frames= 0;
/* Clear The Screen And The Depth Buffer */
 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
 glLoadIdentity();

 glRotatef(map.cam.rot[0],1.0,0.0,0.0);
 glRotatef(map.cam.rot[1],0.0,1.0,0.0);
 glTranslatef(-map.cam.pos[0],-map.cam.pos[1],-map.cam.pos[2]);



 map.render_all_face();

/* Draw it to the screen */
 SDL_GL_SwapBuffers();
/* Gather our frames per second */
 Frames++;
 {
	 GLint t= SDL_GetTicks();
	 if(t-T0>= 5000){
   GLfloat seconds= (t-T0)/1000.0;
   GLfloat fps= Frames/seconds;
   printf("%d frames in %g seconds = %g FPS\n",Frames,seconds,fps);
   T0= t;
   Frames= 0;
	 }
 }
 return(TRUE);
}

int main(int argc,char **argv){
/* Flags to pass to SDL_SetVideoMode */
 int videoFlags;
/* main loop variable */
 int done= FALSE;
/* used to collect events */
 SDL_Event event;
/* this holds some info about our display */
 const SDL_VideoInfo* videoInfo;
/* whether or not the window is active */
 int isActive= TRUE;
/* initialize SDL */
 if(SDL_Init(SDL_INIT_VIDEO)< 0){
  fprintf(stderr,"Video initialization failed: %s\n",SDL_GetError());
  Quit(1);
	}
/* Fetch the video info */
 videoInfo= SDL_GetVideoInfo();
 if(!videoInfo){
  fprintf(stderr,"Video query failed: %s\n",SDL_GetError());
  Quit(1);
	}
/* the flags to pass to SDL_SetVideoMode */
 videoFlags= SDL_OPENGL;          /* Enable OpenGL in SDL */
 videoFlags|= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
 videoFlags|= SDL_HWPALETTE;       /* Store the palette in hardware */
 videoFlags|= SDL_RESIZABLE;       /* Enable window resizing */

/* This checks to see if surfaces can be stored in memory */
 if(videoInfo->hw_available){
	 videoFlags |= SDL_HWSURFACE;
 }else{
	 videoFlags |= SDL_SWSURFACE;
 }

/* This checks if hardware blits can be done */
 if(videoInfo->blit_hw){
	 videoFlags |= SDL_HWACCEL;
 }

/* Sets up OpenGL double buffering */
 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

/* get a SDL surface */
 surface= SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,videoFlags);

/* Verify there is a surface */
 if(!surface){
  fprintf(stderr,"Video mode set failed: %s\n",SDL_GetError());
  Quit(1);
	}

/* initialize OpenGL */
 if(initGL()== FALSE){
  fprintf(stderr,"Could not initialize OpenGL.\n");
  Quit(1);
	}

 GL_Load_Extensions();

/* Resize the initial window */
 resizeWindow(SCREEN_WIDTH,SCREEN_HEIGHT);

 if(argc> 1){
  int x= map.load_bsp(argv[1],5);
  printf("%d\n",x);
  map.load_textures();
 }

/* wait for events */
 bool firstMove;
 while(!done){
/* handle the events in the queue */
 while(SDL_PollEvent(&event))	{
  switch(event.type){
			case SDL_ACTIVEEVENT:
/* Something's happend with our focus
* If we lost focus or we are iconified, we
* shouldn't draw the screen
*/
    if(event.active.gain== 0){
				 isActive= FALSE;
    }else{
     isActive= TRUE;
    }
			 break;
   case SDL_VIDEORESIZE:
/* handle resize event */
			 surface= SDL_SetVideoMode(event.resize.w,event.resize.h,16,videoFlags);
    if(!surface){
     fprintf(stderr,"Could not get a surface after resize: %s\n",SDL_GetError());
     Quit(1);
				}
    resizeWindow( event.resize.w, event.resize.h );
			 break;
			case SDL_KEYDOWN:{
/* handle key presses */
    int key = event.key.keysym.sym;
    keys[key] = 1;
			 handleKeyPress(&event.key.keysym);
    break;
			}
   case SDL_KEYUP:{
    int key = event.key.keysym.sym;
    keys[key] = 0;
    break;
   }
   case SDL_MOUSEMOTION:{
    if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1) && !firstMove){
     map.cam.handle_mouse_motion(event.motion.xrel,event.motion.yrel);
    }else{
     firstMove= false;
    }
    break;
   }
   case SDL_MOUSEBUTTONDOWN:{
    if(event.button.button== SDL_BUTTON_LEFT){
     SDL_ShowCursor(0);
     SDL_WM_GrabInput(SDL_GRAB_ON);
    }
    break;
   }
   case SDL_MOUSEBUTTONUP:{
    if(event.button.button== SDL_BUTTON_LEFT){
     SDL_ShowCursor(1);
     SDL_WM_GrabInput(SDL_GRAB_OFF);
    }
    firstMove = true;
    break;
   }

			case SDL_QUIT:
/* handle quit requests */
			 done= TRUE;
    break;
			default:
			 break;
			}
		}

/* draw the scene */
	 if(isActive){
   map.cam.handle_key_events(keys);
		 drawGLScene();
	 }
	}

/* clean ourselves up and exit */
 Quit(0);

/* Should never get here */
 return 0;
}
